【Security Hub修復手順】[AppSync.5] AWS AppSync GraphQL API は API キーで認証すべきではありません
こんにちは!AWS事業本部の吉田です。
皆さん、お使いのAWS環境のセキュリティチェックはしていますか?
当エントリでは、AWS Security HubによるAWS環境のセキュリティ状況スコアリングに該当する項目についての修復手順をご紹介します。
本記事の対象コントロール
[AppSync.5] AWS AppSync GraphQL API は API キーで認証すべきではありません
[AppSync.5] AWS AppSync GraphQL APIs should not be authenticated with API keys
前提条件
本記事はAWS Security Hubで「AWS基礎セキュリティのベストプラクティススタンダード」を利用されている方向けの内容となります。
AWS Security Hubの詳細についてはこちらのブログをご覧ください。
対象コントロールの説明
本コントールはAWS AppSync GraphQL APIがAPIキーを利用して認証されているかどうかを確認します。
AWS AppSync GraphQL APIがAPIキーを利用して認証されている場合、このコントールは失敗します。
APIキーが流出した場合、攻撃者はGraphQLエンドポイントに不正にアクセスできてしまいます。
そのため、パブリックに公開しても問題ない、もしくは試験運用などのケースを除き、
APIキー認証は避けることをおすすめします。
AWS AppSyncは複数の認証方法があります。
2024年8月現在、5つの認証方法があります。
認証方法 | 特性 | ユースケース |
---|---|---|
APIキー認証 | 簡単に設定可能。固定のAPIキーを使用。低セキュリティ | 試験運用。パブリックAPI |
LAMBDA認証 | カスタムロジックで認証・認可可能。柔軟性高い | カスタム承認ロジックが必要な場合 |
IAM認証 | AWSリソースへのアクセス制御 | AWSリソースとの連携が必要なアプリケーション(バックエンド) |
OpenID Connect認証 | 外部IDプロバイダーと連携 | Auth0などの外部認証プロバイダーを使用するアプリケーション |
Cognito ユーザープール | ユーザー管理が可能。ユーザープールのグループ単位で細やかなアクセス制御が可能。 | ユーザーログインが必要なアプリケーション。セキュリティ要件が高いアプリケーション |
これらの認証方法の中で、APIキー認証以外の認証方法に切り替えますと、本コントールが修復されます。
認証方法の変更は非常に影響が大きいため、慎重に作業することをおすすめします。
(開発環境で動作確認した後に本番環境に適用する、メンテナンス時間を設けるなど)
修復手順
AWS側設定
今回は認証方法をAPIキーからCognitoユーザープールに切り替える方法を記載します。
どの認証方法に切り替えるかは、それぞれの認証方法の特性を考慮して検討してください。
事前準備
- 事前にCognitoユーザープール・アプリクライアントを作成してください。
本作業
-
対象となるAppSyncを選択し、「編集」をクリックします。
-
左サイドバーの「設定」をクリックします。
-
プライマリ認可モードの「編集」をクリックします。
-
認証モードを「APIキー」から「Amazon Cognito ユーザープール」に変更します。
-
Cognitoユーザープールの設定をします。作成したユーザープールを設定してください。
デフォルトのアクションに関しては、認可の有無で判断してください。
それぞれのアクションの内容は以下の通りです。
- ALLOW
- 認証済みのユーザーは、すべてのGraphQL操作が可能
- DENY
- 認証済みのユーザーでも、スキーマに@aws_auth定義がないとGraphQL操作不能
- @aws_authを利用することで、Cognitoユーザープールのユーザーグループ単位でGraphQL操作を制限可能
設定しましたら、「保存」をクリックします
- 現在の設定(APIキー)を削除しても問題ないか確認するポップが表示されます。
「削除する代わりに、APIキーを追加の認証モードにする」というチェックボックスがあります。
AppSyncは複数の認証モードがサポートとされています。
そのため、
- Cognitoユーザープールをプライマリ認証モード
- APIキー認証を追加の認証モード
という風に設定することが可能です。
Cognitoユーザープールの動作確認をしてからAPIキーを削除したい、開発期間中はAPIキー認証をしたいなどといった場合は、このチェックボックスにチェックをつけてください。
その場合、APIキー認証を利用するためにスキーマの修正が必要となります。
スキーマの修正に関しては、こちらのブログの
のセクションをご覧ください。
変更を確認できましたら、入力欄に「確認」と入力して、「確認」をクリックしてください。
-
プライマリ認可モードが「Amazon Cognito ユーザープール」に変更されていることを確認します。
-
(任意)手順6でAPIキー認証を追加の認証モードにした後、APIキー認証が不要となった場合、当手順を実施してください。
追加の認可モードで削除対象のAPIキーを選択し、「削除」をクリックします。
APIキーが削除されたことを確認します。
クライアント側修正
ここから記載する手順は、あくまで参考情報です。
その点、ご了承ください。
APIキー認証の場合のクエリ
APIキー認証の際は、APIキーを利用してクエリをします。
以下のコードは、Node.js環境(Jest)でaxiosで実行するコードです。
このコードは、こちらのブログの
のセクションのコードを参考にしました。
import axios from 'axios';
const API_URL = process.env.API_URL as string;
const API_KEY = process.env.API_KEY as string;
const query = `
query MyQuery {
listUsers(limit: 10) {
items {
age
id
name
}
}
}`;
it('データ取得', async () => {
const response = await axios.post(
API_URL,
{
query: query,
},
{
headers: {
'x-api-key': API_KEY,
},
}
);
console.log(JSON.stringify(response.data));
});
無事データを取得することが出来ました。
Cognito ユーザープールの場合のクエリ
AppSyncの認証をAPIキー認証からCognitoユーザープールに切り替える場合、
Cognitoユーザープールを使用してJWTトークンを取得し、そのトークンをHTTPリクエストのAuthorizationヘッダーに渡す必要があります。
上記のコードを以下のように修正します。
import axios from 'axios';
import * as AmazonCognitoIdentity from 'amazon-cognito-identity-js';
const API_URL = process.env.API_URL as string;
const COGNITO_USER_POOL_ID = process.env.COGNITO_USER_POOL_ID as string;
const COGNITO_CLIENT_ID = process.env.COGNITO_CLIENT_ID as string;
const COGNITO_USERNAME = process.env.COGNITO_USERNAME as string;
const COGNITO_PASSWORD = process.env.COGNITO_PASSWORD as string;
const query = `
query MyQuery {
listUsers(limit: 10) {
items {
age
id
name
}
}
}`;
// Cognitoユーザー認証を行い、JWTトークンを取得する関数
async function getCognitoToken(): Promise<string> {
const authenticationDetails = new AmazonCognitoIdentity.AuthenticationDetails({
Username: COGNITO_USERNAME,
Password: COGNITO_PASSWORD,
});
const poolData = {
UserPoolId: COGNITO_USER_POOL_ID,
ClientId: COGNITO_CLIENT_ID,
};
const userPool = new AmazonCognitoIdentity.CognitoUserPool(poolData);
const userData = {
Username: COGNITO_USERNAME,
Pool: userPool,
};
const cognitoUser = new AmazonCognitoIdentity.CognitoUser(userData);
return new Promise((resolve, reject) => {
cognitoUser.authenticateUser(authenticationDetails, {
onSuccess: (result) => {
const idToken = result.getIdToken().getJwtToken();
resolve(idToken);
},
onFailure: (err) => {
reject(err);
},
});
});
}
it('データ取得', async () => {
try {
// JWTトークンを取得
const token = await getCognitoToken();
// AppSync APIを呼び出す
const response = await axios.post(
API_URL,
{
query: query,
},
{
headers: {
Authorization: token,
},
}
);
console.log(JSON.stringify(response.data));
} catch (error) {
console.error('Error fetching data:', error);
}
}, 10000); // タイムアウトを10秒に設定
認証方法が切り替わっても、無事データを取得することが出来ました。
Cognitoユーザープールの動作確認をするために一時的にAPIキー認証を追加の認証モードにしていた場合、
AWS側設定の本作業の手順8を参考にしてAPIキーを削除してください。
最後に
今回は、AWS Security HubによるAWS環境のセキュリティ状況スコアリングに該当する項目についての修正手順をご紹介しました。
コントロールを修正して、お使いのAWS環境のセキュリティをパワーアップさせましょう!
最後までお読みいただきありがとうございました!どなたかのお役に立てれば幸いです。